package com.itaming.lycheeframework.support.utils;

import lombok.experimental.UtilityClass;
import org.springframework.util.Assert;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;

/**
 * Object工具类
 *
 * @author A.Ming
 */
@UtilityClass
public class ObjectUtil {

    /**
     * 判断对象是否为数组
     *
     * @param obj 对象
     * @return boolean
     */
    public static boolean isArray(Object obj) {
        return obj != null && obj.getClass().isArray();
    }

    /**
     * 是否为 {@code null}
     *
     * @param obj 对象
     * @return boolean
     */
    public static boolean isNull(Object obj) {
        return obj == null;
    }

    /**
     * 是否不为 {@code null}
     *
     * @param obj 对象
     * @return boolean
     */
    public static boolean isNotNull(Object obj) {
        return obj != null;
    }

    /**
     * 判断对象是否为空
     *
     * @param obj 对象
     * @return boolean
     */
    public static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }

        if (obj instanceof Optional) {
            return ((Optional<?>) obj).isEmpty();
        }

        if (obj instanceof CharSequence) {
            return ((CharSequence) obj).isEmpty();
        }

        if (isArray(obj)) {
            return Array.getLength(obj) == 0;
        }

        if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        }

        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        }

        return false;
    }

    /**
     * 判断对象是否不为空
     *
     * @param obj 对象
     * @return boolean
     */
    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }

    /**
     * 判断是否任意对象为 {@code null}
     *
     * @param objects 对象数组
     * @return boolean
     */
    public static boolean isAnyNull(Object... objects) {
        return ArrayUtil.isAnyNull(objects);
    }

    /**
     * 判断是否是否任意对象不为 {@code null}
     *
     * @param objects 对象数组
     * @return boolean
     */
    public static boolean isAnyNotNull(Object... objects) {
        return ArrayUtil.isAnyNotNull(objects);
    }

    /**
     * 判断是否所有对象均为 {@code null}
     *
     * @param objects 对象数组
     * @return boolean
     */
    public static boolean isAllNull(Object... objects) {
        return ArrayUtil.isAllNull(objects);
    }

    /**
     * 判断是否所有对象均不为 {@code null}
     *
     * @param objects 对象数组
     * @return boolean
     */
    public static boolean isAllNotNull(Object... objects) {
        return ArrayUtil.isAllNotNull(objects);
    }

    /**
     * 判断是否任意对象为空
     *
     * @param objects 对象数组
     * @return boolean
     */
    public static boolean isAnyEmpty(Object... objects) {
        return ArrayUtil.isAnyEmpty(objects);
    }

    /**
     * 判断是否任意对象不为空
     *
     * @param objects 对象数组
     * @return boolean
     */
    public static boolean isAnyNotEmpty(Object... objects) {
        return ArrayUtil.isAnyNotEmpty(objects);
    }

    /**
     * 判断是否所有对象均为空
     *
     * @param objects 对象数组
     * @return boolean
     */
    public static boolean isAllEmpty(Object... objects) {
        return ArrayUtil.isAllEmpty(objects);
    }

    /**
     * 判断是否所有对象均不为空
     *
     * @param objects 对象数组
     * @return boolean
     */
    public static boolean isAllNotEmpty(Object... objects) {
        return ArrayUtil.isAllNotEmpty(objects);
    }

    /**
     * 对象为 {@code null} 时返回默认值
     *
     * @param object       对象
     * @param defaultValue 默认值
     * @return T
     */
    public static <T> T defaultIfNull(T object, T defaultValue) {
        return object != null ? object : defaultValue;
    }

    /**
     * 对象为 {@code null} 时返回默认值
     *
     * @param object               对象
     * @param defaultValueSupplier 默认值提供函数
     * @return T
     */
    public static <T> T defaultIfNull(T object, Supplier<T> defaultValueSupplier) {
        return object != null
            ? object
            : defaultValueSupplier != null ? defaultValueSupplier.get() : null;
    }

    /**
     * 对象为 {@code null} 时抛出异常
     *
     * @param object            对象
     * @param exceptionSupplier 异常提供函数
     * @return 返回原对象
     */
    public static <T> T throwIfNull(T object, Supplier<? extends RuntimeException> exceptionSupplier) {
        Assert.notNull(exceptionSupplier, "Exception supplier must be not null");
        if (object == null) {
            throw exceptionSupplier.get();
        }
        return object;
    }

    /**
     * 对象转字符串
     *
     * @param obj 对象
     * @return 字符串，参数为 {@code null} 时返回 {@code null}
     */
    public static String toString(Object obj) {
        return toString(obj, false);
    }

    /**
     * 对象转字符串
     *
     * @param obj         对象
     * @param nullToEmpty 是否在对象为 {@code null} 时返回空字符串
     * @return 字符串
     */
    public static String toString(Object obj, boolean nullToEmpty) {
        return obj != null
            ? obj.toString()
            : nullToEmpty ? StringPool.EMPTY : null;
    }

    /**
     * 包装类型转为基本类型
     *
     * @param object       包装类对象
     * @param valueForNull 对象为 {@code null} 时的默认值
     * @return 基本类型值
     */
    public static boolean toPrimitive(Boolean object, boolean valueForNull) {
        return object != null ? object : valueForNull;
    }

    /**
     * 包装类型转为基本类型
     *
     * @param object       包装类对象
     * @param valueForNull 对象为 {@code null} 时的默认值
     * @return 基本类型值
     */
    public static byte toPrimitive(Byte object, byte valueForNull) {
        return object != null ? object : valueForNull;
    }

    /**
     * 包装类型转为基本类型
     *
     * @param object       包装类对象
     * @param valueForNull 对象为 {@code null} 时的默认值
     * @return 基本类型值
     */
    public static char toPrimitive(Character object, char valueForNull) {
        return object != null ? object : valueForNull;
    }

    /**
     * 包装类型转为基本类型
     *
     * @param object       包装类对象
     * @param valueForNull 对象为 {@code null} 时的默认值
     * @return 基本类型值
     */
    public static double toPrimitive(Double object, double valueForNull) {
        return object != null ? object : valueForNull;
    }

    /**
     * 包装类型转为基本类型
     *
     * @param object       包装类对象
     * @param valueForNull 对象为 {@code null} 时的默认值
     * @return 基本类型值
     */
    public static float toPrimitive(Float object, float valueForNull) {
        return object != null ? object : valueForNull;
    }

    /**
     * 包装类型转为基本类型
     *
     * @param object       包装类对象
     * @param valueForNull 对象为 {@code null} 时的默认值
     * @return 基本类型值
     */
    public static int toPrimitive(Integer object, int valueForNull) {
        return object != null ? object : valueForNull;
    }

    /**
     * 包装类型转为基本类型
     *
     * @param object       包装类对象
     * @param valueForNull 对象为 {@code null} 时的默认值
     * @return 基本类型值
     */
    public static long toPrimitive(Long object, long valueForNull) {
        return object != null ? object : valueForNull;
    }

    /**
     * 包装类型转为基本类型
     *
     * @param object       包装类对象
     * @param valueForNull 对象为 {@code null} 时的默认值
     * @return 基本类型值
     */
    public static short toPrimitive(Short object, short valueForNull) {
        return object != null ? object : valueForNull;
    }

}
